'use strict';

const BbPromise = require('bluebird');
const _ = require('lodash');

module.exports = {
  compileMethods() {
    this.permissionMapping = [];

    this.validated.events.forEach(event => {
      const resourceId = this.getResourceId(event.http.path);
      const resourceName = this.getResourceName(event.http.path);

      const requestParameters = {};
      if (event.http.request && event.http.request.parameters) {
        _.forEach(event.http.request.parameters, (value, key) => {
          requestParameters[key] = value.required === undefined ? value : value.required;
        });
      }

      const template = {
        Type: 'AWS::ApiGateway::Method',
        Properties: {
          HttpMethod: event.http.method.toUpperCase(),
          RequestParameters: requestParameters,
          ResourceId: resourceId,
          RestApiId: this.provider.getApiGatewayRestApiId(),
          OperationName: event.http.operationId,
        },
      };

      if (event.http.private) {
        template.Properties.ApiKeyRequired = true;
      } else {
        template.Properties.ApiKeyRequired = false;
      }

      const methodLogicalId = this.provider.naming.getMethodLogicalId(
        resourceName,
        event.http.method
      );
      const validatorLogicalId = this.provider.naming.getValidatorLogicalId(
        resourceName,
        event.http.method
      );
      const lambdaLogicalId = this.provider.naming.getLambdaLogicalId(event.functionName);
      const functionObject = this.serverless.service.functions[event.functionName];
      const lambdaAliasName = functionObject.targetAlias && functionObject.targetAlias.name;
      const lambdaAliasLogicalId =
        functionObject.targetAlias && functionObject.targetAlias.logicalId;

      const singlePermissionMapping = {
        resourceName,
        lambdaLogicalId,
        lambdaAliasName,
        lambdaAliasLogicalId,
        event,
      };
      this.permissionMapping.push(singlePermissionMapping);

      _.merge(
        template,
        this.getMethodAuthorization(event.http),
        this.getMethodIntegration(event.http, {
          lambdaLogicalId,
          lambdaAliasName,
        }),
        this.getMethodResponses(event.http)
      );

      let extraCognitoPoolClaims;
      if (event.http.authorizer) {
        const claims = event.http.authorizer.claims || [];
        extraCognitoPoolClaims = claims.map(claim => {
          if (typeof claim === 'string') {
            const colonIndex = claim.indexOf(':');
            if (colonIndex !== -1) {
              const subClaim = claim.substring(colonIndex + 1);
              return `"${subClaim}": "$context.authorizer.claims['${claim}']"`;
            }
          }
          return `"${claim}": "$context.authorizer.claims.${claim}"`;
        });
      }
      const requestTemplates = template.Properties.Integration.RequestTemplates;
      _.forEach(requestTemplates, (value, key) => {
        let claimsString = '';
        if (extraCognitoPoolClaims && extraCognitoPoolClaims.length > 0) {
          claimsString = extraCognitoPoolClaims.join(',').concat(',');
        }
        requestTemplates[key] = value.replace('extraCognitoPoolClaims', claimsString);
      });

      this.apiGatewayMethodLogicalIds.push(methodLogicalId);

      if (event.http.request && event.http.request.schema) {
        for (const requestSchema of _.entries(event.http.request.schema)) {
          const contentType = requestSchema[0];
          const schema = requestSchema[1];

          const modelLogicalId = this.provider.naming.getModelLogicalId(
            resourceName,
            event.http.method,
            contentType
          );

          template.Properties.RequestValidatorId = { Ref: validatorLogicalId };
          template.Properties.RequestModels = template.Properties.RequestModels || {};
          template.Properties.RequestModels[contentType] = { Ref: modelLogicalId };

          _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, {
            [modelLogicalId]: {
              Type: 'AWS::ApiGateway::Model',
              Properties: {
                RestApiId: this.provider.getApiGatewayRestApiId(),
                ContentType: contentType,
                Schema: schema,
              },
            },
            [validatorLogicalId]: {
              Type: 'AWS::ApiGateway::RequestValidator',
              Properties: {
                RestApiId: this.provider.getApiGatewayRestApiId(),
                ValidateRequestBody: true,
                ValidateRequestParameters: true,
              },
            },
          });
        }
      }

      _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, {
        [methodLogicalId]: template,
      });
    });

    return BbPromise.resolve();
  },
};
